//
//  PutObject.swift
//  COSDemo
//
//  示例：使用永久密钥上传文件到腾讯云 COS
//  注意：仅在本地开发测试阶段使用永久密钥，正式环境请改用临时密钥
//

import Foundation
import QCloudCOSXML


/// 签名提供者示例（使用永久密钥）
/// 正式环境务必使用临时密钥并实现安全的密钥管理
class PermanentSignatureProvider: NSObject, QCloudSignatureProvider {

    func signature(with fields: QCloudSignatureFields!,
                   request: QCloudBizHTTPRequest!,
                   urlRequest: NSMutableURLRequest!,
                   compelete continueBlock: QCloudHTTPAuthentationContinueBlock!) {

        let credential = QCloudCredential()

        //最小权限密钥
         credential.secretID = "AKIDhIjwytywqdG5nIdqtnbGxshOxLtKdu58"
                credential.secretKey = "uZ6Z0Qly23vc5OXdcO8jeSIxZ2TsBc2X"

        // 使用 V5 鉴权方式生成签名
        let creator = QCloudAuthentationV5Creator(credential: credential)

        // 注意：不要对 urlRequest 执行 copy 或 mutableCopy 操作
        let signature = creator?.signature(forData: urlRequest)
        continueBlock(signature, nil)
    }
}

/// PutObject 示例
class PutObject {
    private static var isServiceConfigured = false
    private static var defaultRegion: String = "ap-shanghai"

    /// 初始化 COS 服务
    /// - Parameter domainURLString: 自定义源站或加速域名（可选），若无需求可传 nil 使用默认域名
    /// - Parameter region: 存储桶所属地域（如 "ap-beijing", "ap-guangzhou"）
    static func setupCOSService(domainURLString: String? = nil,
                                region: String = defaultRegion) {
        if isServiceConfigured {
            return
        }
        isServiceConfigured = true
        defaultRegion = region

        // 1. 构造 EndPoint
        let endpoint: QCloudCOSXMLEndPoint
        if let domain = domainURLString,
           let domainURL = URL(string: domain) {
            // 使用自定义域名
            endpoint = QCloudCOSXMLEndPoint(literalURL: domainURL)
        } else {
            // 如果不传自定义域名，SDK 会自动解析默认域名
            endpoint = QCloudCOSXMLEndPoint()
        }

        // 使用 HTTPS
        endpoint.useHTTPS = true

        // Ensure endpoint uses the configured region
        endpoint.regionName = region

        // 2. 创建配置对象
        let config = QCloudServiceConfiguration()
        config.endpoint = endpoint

        // 3. 设置签名回调（使用永久密钥进行测试）
        config.signatureProvider = PermanentSignatureProvider()

        // 4. 注册默认 COS 服务
        QCloudCOSXMLService.registerDefaultCOSXML(with: config)

        // 5. 注册默认 TransferManger
        QCloudCOSTransferMangerService.registerDefaultCOSTransferManger(with: config)
    }

    /// 上传单个本地文件
    /// - Parameters:
    ///   - filePath: 本地文件路径
    ///   - objectKey: COS 上的完整对象键（包含路径），例如 "testFolder/test.mp4"
    ///   - bucket: 存储桶名称（形如 "examplebucket-1250000000"）
    ///   - region: 地区名称（形如 "ap-shanghai"）
    ///   - progress: 进度回调（可选）
    ///   - completion: 结果回调(uploadedFileURL, QCloudUploadObjectResult?, Error?)
    static func uploadLocalFile(filePath: String,
                                objectKey: String,
                                bucket: String,
                                region: String,
                                progress: ((Int64, Int64, Int64) -> Void)? = nil,
                                completion: @escaping (URL?, QCloudUploadObjectResult?, Error?) -> Void) {

        let safeRegion = region.isEmpty ? "ap-shanghai" : region
        
        print("[Upload] bucket = \(bucket), region = \(region), objectKey = \(objectKey) , filePath = \(filePath)")
        // 1. 创建上传请求
        let putRequest = QCloudCOSXMLUploadObjectRequest<AnyObject>()

        // 2. 指定目标存储桶
        putRequest.bucket = bucket
        // 2.1 指定目标regionName
        
        putRequest.regionName = safeRegion
        
        
        // 3. 指定对象键
        putRequest.object = objectKey

        // 4. 设置要上传的本地文件
        let fileURL: URL
        if filePath.hasPrefix("file://") {
            fileURL = URL(string: filePath)!
        } else {
            fileURL = URL(fileURLWithPath: filePath)
        }
        putRequest.body = fileURL as AnyObject

        // 5. 上传进度回调（可选）
        putRequest.sendProcessBlock = { bytesSent, totalBytesSent, totalBytesExpectedToSend in
            progress?(bytesSent, totalBytesSent, totalBytesExpectedToSend)
        }
        
        // 6. 完成回调，打印 requestId 并回调结果
        putRequest.setFinish { (outputObject, error) in
            
            // 尝试从成功或失败中获取 HTTPURLResponse 并打印 requestId
            var httpResponse: HTTPURLResponse?
            if let resp = outputObject?.__originHTTPURLResponse__ {
                httpResponse = resp
            } else if let nsError = error as NSError?,
                      let resp = nsError.userInfo["__originHTTPURLResponse__"] as? HTTPURLResponse {
                httpResponse = resp
            }
            if let response = httpResponse,
               let requestId = response.allHeaderFields["x-cos-request-id"] as? String {
                print("[Upload] requestId = \(requestId)")
            }

            // 构造文件访问 URL
            let fileURLString = "https://\(bucket).cos.\(safeRegion).myqcloud.com/\(objectKey)"
            let fileURL = URL(string: fileURLString)
            print("[Upload] fileURL = \(fileURLString)")
            completion(fileURL, outputObject, error)
        }

        // 7. 发起上传
        QCloudCOSTransferMangerService.defaultCOSTransferManager().uploadObject(putRequest)
    }

    /// 批量上传多个本地文件
    /// - Parameters:
    ///   - filePaths: 本地文件路径数组
    ///   - bucket: 存储桶名称（形如 "examplebucket-1250000000"）
    ///   - folder: COS 上的目录前缀，可为空
    ///   - region: 地区名称（形如 "ap-shanghai"）
    ///   - onSingleFinish: 单个文件上传完成回调（可选）
    ///   - onAllFinish: 全部文件完成回调
    static func batchUploadLocalFiles(filePaths: [String],
                                      bucket: String,
                                      region: String,
                                      folder: String? = nil,
                                      onSingleFinish: ((Int, String, URL?, QCloudUploadObjectResult?, Error?) -> Void)? = nil,
                                      onAllFinish: (() -> Void)? = nil) {

        // 使用 DispatchGroup 来监听所有上传是否完成
        let uploadGroup = DispatchGroup()

        for (index, path) in filePaths.enumerated() {
            uploadGroup.enter()

            // 生成对象键：如有 folder 则拼接 folder 前缀
            let fileName = (path as NSString).lastPathComponent
            let objectKey = folder == nil ? fileName : "\(folder!)/\(fileName)"

            // 发起单个文件上传
            uploadLocalFile(filePath: path, objectKey: objectKey, bucket: bucket, region: region) { fileURL, result, error in
                // 单文件上传结束
                onSingleFinish?(index, path, fileURL, result, error)
                uploadGroup.leave()
            }
        }

        // 当全部文件都上传完毕后回调
        uploadGroup.notify(queue: .main) {
            onAllFinish?()
        }
    }
}
